﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsFormsApplication1;

namespace _2013_ece_csharp_snake
{
    public class GameZone
    {
        public static int NORMAL = 0;
        public static int IMPORTED = 1;
        private int mode;
        private System.Windows.Forms.Panel panel;
        private WindowsFormsApplication1.FormDemo form;
        private Snake snake;
        private IList<rect> bodyRect;
        private IList<rect> walls;
        private int last;
        private bool newWall;
        private Point wall;
        private rect fruit;
        public int Score { get; set; }

        private EndForm end;

        public string Name { get; set; }


        public GameZone(System.Windows.Forms.Panel panel, WindowsFormsApplication1.FormDemo form, int mode, string name)
        {
            this.panel = panel;
            this.mode = mode;
            this.form = form;

            this.Name = name;

            newWall = false;

            snake = new Snake(panel);
            bodyRect = new List<rect>();
            walls = new List<rect>();
            bodyRect.Add(new rect(panel, snake.Size.X, Color.Red));
            last = 0;
            Score = 0;

            fruit = new rect(panel, snake.Size.X-5, Color.Blue);
            //fruit.randomPosition(walls, bodyRect);
            fruit.randomPosition(walls, bodyRect);
            fruit.setVisible(true);
        }

        public void actualiser()
        {
            if (mode == NORMAL)
            {
                // Test if wall received
                testNewWall();

                // actualise Snake position
                snake.actuPos();
                // prepare the data to be sent threw the network
                snake.prepareDataSend();

                Point position = new Point(bodyRect[last].Location.X, bodyRect[last].Location.Y);
                position.X = snake.Body[0].X - snake.Size.X / 2 - panel.Left;
                position.Y = snake.Body[0].Y - snake.Size.Y / 2 - panel.Top;
                bodyRect[last].Location = position;

                bodyRect[last].setVisible(true);

                // check fruit
                checkManger();

                // Check Collision
                if (checkMort() == true)
                {
                    form.Timer1.Enabled = false;
                    //MessageBox.Show("Perdu");
                    saveData();
                    displayEnd();
                }

                last--;
                if (last < 0)
                    last = snake.Lenght - 1;

                // check collision
                snake.checkWall(panel.Top, panel.Bottom, panel.Left, panel.Right);

            }
            else
            {
                snake.handleDataReceived();

                
                IList<Point> b = snake.Body;

                //for (int i = 0; i < b.Count; i++)
                for (int i = 0; i < 1; i++)
                {
                    if (b.Count > 0)
                    {
                        if (i >= bodyRect.Count)
                        {
                            bodyRect.Add(new rect(panel, snake.Size.X, Color.Red));
                        }

                        bodyRect[i].Left = (int)b[i].X - snake.Size.X / 2 - panel.Left;
                        bodyRect[i].Top = (int)b[i].Y - snake.Size.Y / 2 - panel.Top;

                        bodyRect[i].setVisible(true);
                    }
                }

                //bodyRect[last].Left = snake.Head.X - snake.Size.X / 2 - panel.Left;
                //bodyRect[last].Top = snake.Head.Y - snake.Size.Y / 2 - panel.Top;

            }
        }

        public void grow()
        {
            rect temp;

            for (int i = 0; i < 20; i++)
            {
                snake.grow();
                temp = new rect(panel, snake.Size.X, Color.Red);
                temp.Left = -50;
                temp.Top = -50;
                bodyRect.Insert(last, temp);
            }
            last += 20;
        }

        public bool checkMort()
        {

            for (int i = 0; i < bodyRect.Count; i++)
            {
                if ((i != last && i + bodyRect.Count != last) &&
                    (i != last + 1 && i + bodyRect.Count != last + 1) &&
                    (i != last + 2 && i + bodyRect.Count != last + 2) &&
                    (i != last + 3 && i + bodyRect.Count != last + 3) &&
                    (i != last + 4 && i + bodyRect.Count != last + 4) &&
                    (i != last + 5 && i + bodyRect.Count != last + 5) &&
                    (i != last + 6 && i + bodyRect.Count != last + 6) &&
                    (i != last + 7 && i + bodyRect.Count != last + 7) &&
                    (i != last + 8 && i + bodyRect.Count != last + 8) &&
                    (i != last + 9 && i + bodyRect.Count != last + 9) &&
                    (i != last + 10 && i + bodyRect.Count != last + 10) &&
                    (i != last + 11 && i + bodyRect.Count != last + 11) &&
                    (i != last + 12 && i + bodyRect.Count != last + 12) &&
                    (i != last + 13 && i + bodyRect.Count != last + 13) &&
                    (i != last + 14 && i + bodyRect.Count != last + 14) &&
                    (i != last + 15 && i + bodyRect.Count != last + 15) &&
                    (i != last + 16 && i + bodyRect.Count != last + 16))
                        if (checkCollision(bodyRect[i].Top, bodyRect[last].Top,
                                           bodyRect[i].Bottom, bodyRect[last].Bottom,
                                           bodyRect[i].Left, bodyRect[last].Left,
                                           bodyRect[i].Right, bodyRect[last].Right))
                        {
                            return true;
                        }
            }

            for (int i = 0; i < walls.Count; i++)
            {
                if (checkCollision(bodyRect[last].Top, walls[i].Top,
                                   bodyRect[last].Bottom, walls[i].Bottom,
                                   bodyRect[last].Left, walls[i].Left,
                                   bodyRect[last].Right, walls[i].Right))
                {
                    return true;
                }
            }

            return false;
        }

        public void checkManger()
        {
            if (checkCollision(bodyRect[last].Top, fruit.Top,
                               bodyRect[last].Bottom, fruit.Bottom,
                               bodyRect[last].Left, fruit.Left,
                               bodyRect[last].Right, fruit.Right))
            {
                sendWall();
                fruit.randomPosition(walls);
                Score++;
                grow();
            }
        }

        public void sendWall()
        {
            Point temp = snake.Data.wall;

            temp.X = fruit.Left;
            temp.Y = fruit.Top;

            snake.Data.wall = temp;

            snake.Data.newWall = true;
        }

        public void testNewWall()
        {
            if (newWall == true)
            {
                newWall = false;
                addWall(wall);

            }
        }

        public void addWall(Point p)
        {

            rect r = new rect(panel, snake.Size.X, Color.Black);
            r.Left = p.X;
            r.Top = p.Y;
            r.setVisible(true);
            walls.Add(r);
        }

        public static bool checkCollision(int top1, int top2, 
                                   int bottom1, int bottom2,
                                   int left1, int left2,
                                   int right1, int right2)
        {
            if (bottom1 > top2 &&
                top1 < bottom2 &&
                right1 > left2 &&
                left1 < right2)
            {
                return true;
            }
            else
                return false;
        }

        private void sendPosition()
        {

        }

        private void displayEnd()
        {
            Thread t = new Thread(new ParameterizedThreadStart(WindowsFormsApplication1.FormDemo.startEndForm));
            t.Start(Score);
            form.Close();
        }

        private void saveData()
        {
            Data data = new Data(this.Score, this.Name);
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(data.GetType());
            System.IO.StreamWriter file = new System.IO.StreamWriter(@"Historique.xml");
            x.Serialize(file, data);
            file.Close(); // Release resources

            try
            {
                // Creating a StreamWriter to save data
                StreamWriter monStreamWriter = new StreamWriter(@"LogScore.snak", true);
                
                // Writing
                monStreamWriter.WriteLine(this.Score);

                // Closing stream reader
                monStreamWriter.Close();
            }
            catch (Exception ex)
            {
                // Code exécuté en cas d'exception 
                Console.WriteLine("Erreur");
            }
        }

        public Snake Snake
        {
            get { return snake; }
            set { snake = value; }
        }

        internal IList<rect> BodyRect
        {
            get { return bodyRect; }
            set { bodyRect = value; }
        }

        public int Last
        {
            get { return last; }
            set { last = value; }
        }

        public bool NewWall
        {
            get { return newWall; }
            set { newWall = value; }
        }

        public Point Wall
        {
            get { return wall; }
            set { wall = value; }
        }
    }
}
